Add (crude) support for Garmin Training Center.
authorrobertl <robertl>
Fri, 25 Aug 2006 03:54:47 +0000 (03:54 +0000)
committerrobertl <robertl>
Fri, 25 Aug 2006 03:54:47 +0000 (03:54 +0000)
Makefile.in
gbser_win.c
gtrnctr.c [new file with mode: 0644]
vecs.c
xmldoc/formats/gtrnctr.xml [new file with mode: 0644]

index 839cf4af37628136ac7284ff96d9ad5aeacbeabc..59a4e8500286f0e60201ee9887143cf18701cef0 100644 (file)
@@ -53,7 +53,7 @@ FMTS=magproto.o gpx.o geo.o mapsend.o mapsource.o garmin_tables.o \
        tef_xml.o maggeo.o pathaway.o vitosmt.o gdb.o bcr.o coto.o \
        ignrando.o stmwpp.o msroute.o cst.o nmn4.o mag_pdb.o compegps.o \
        yahoo.o unicsv.o wfff_xml.o garmin_txt.o axim_gpb.o gpssim.o \
-       wbt-200.o stmsdf.o
+       wbt-200.o stmsdf.o gtrnctr.o
 
 FILTERS=position.o duplicate.o arcdist.o polygon.o smplrout.o \
        reverse_route.o sort.o stackfilter.o trackfilter.o discard.o \
index a339cf86a6013fb7206704e6a70c883831504a51..26b897e84f07c4b2975eea4ef37f835956f46387 100644 (file)
@@ -1,3 +1,4 @@
+#define ERROR_TIMEOUT 0x4321
 /*
     Serial interface - Windows layer.
     
diff --git a/gtrnctr.c b/gtrnctr.c
new file mode 100644 (file)
index 0000000..ff81ba9
--- /dev/null
+++ b/gtrnctr.c
@@ -0,0 +1,302 @@
+/*
+    Access Garmin Training Center (Forerunner/Foretracker/Edge) data files.
+
+    Copyright (C) 2006 Robert Lipe, robertlipe@usa.net
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+ */
+
+#include "defs.h"
+#include "xmlgeneric.h"
+
+static FILE *ofd;
+static waypoint *wpt_tmp;
+static route_head *trk_head;
+
+#define MYNAME "gtc"
+
+static
+arglist_t gtc_args[] = {
+       ARG_TERMINATOR
+};
+#if 0
+/* Tracks */
+static xg_callback     gl_trk_s;
+// static xg_callback  gl_trk_ident;
+static xg_callback     gl_trk_pnt_s, gl_trk_pnt_e;
+static xg_callback     gl_trk_utc;
+static xg_callback     gl_trk_lat;
+static xg_callback     gl_trk_long;
+static xg_callback     gl_trk_alt;
+
+static xg_tag_mapping gl_map[] = {
+ { gl_trk_s,    cb_start, "/History/Run/Track" },
+ { gl_trk_pnt_s,cb_start, "/History/Run/Track/Trackpoint/Position" },
+ { gl_trk_pnt_e,cb_end,   "/History/Run/Track/Trackpoint/Position" },
+ { gl_trk_lat,  cb_cdata, "/History/Run/Track/Trackpoint/Position/Latitude" },
+ { gl_trk_long, cb_cdata, "/History/Run/Track/Trackpoint/Position/Longitude" },
+ { gl_trk_alt,  cb_cdata, "/History/Run/Track/Trackpoint/Position/Altitude" },
+ { gl_trk_utc,  cb_cdata, "/History/Run/Track/Trackpoint/Time" },
+ { NULL,       0,         NULL}
+};
+#endif
+
+static void
+gtc_rd_init(const char *fname)
+{
+       fatal(MYNAME ": this format does not support reading.\n");
+}
+
+#if 0
+static void
+gtc_read(void)
+{
+       xml_read();
+}
+
+static void
+gtc_rd_deinit(void)
+{
+       xml_deinit();
+}
+#endif
+
+static void
+gtc_wr_init(const char *fname)
+{
+        ofd = xfopen(fname, "w", MYNAME);
+}
+
+static void
+gtc_wr_deinit(void)
+{
+        fclose(ofd);
+}
+
+static int gtc_indent_level;
+static void 
+gtc_write_xml(int indent, const char *fmt, ...)
+{
+       va_list args;
+       int i;
+       va_start(args, fmt);
+
+       if (indent < 0) gtc_indent_level--;
+
+       for (i = 0; i < gtc_indent_level; i++) {
+               fputs("  ", ofd);
+       }
+
+       vfprintf(ofd, fmt, args);
+
+       if (indent > 0) gtc_indent_level++;
+
+       va_end(args);
+
+}
+
+static void
+gtc_waypt_pr(const waypoint *wpt)
+{      
+#if 0
+       fprintf(ofd, "            <Trackpoint>\n");
+       fprintf(ofd, "                <Position>\n");
+       fprintf(ofd, "                    <Latitude>%.5f</Latitude>\n", wpt->latitude);
+       fprintf(ofd, "                    <Longitude>%.5f</Longitude>\n", wpt->longitude);
+       if (wpt->altitude != unknown_alt) {
+               fprintf(ofd, "                    <Altitude>%.3f</Altitude>\n", wpt->altitude);
+       }
+       fprintf(ofd, "                </Position>\n");
+       fprintf(ofd, "                ");
+       xml_write_time(ofd, wpt->creation_time, "Time");
+       fprintf(ofd, "            </Trackpoint>\n");
+#else
+       gtc_write_xml(1, "<Trackpoint>\n");
+       if (wpt->creation_time) {
+               char time_string[100];
+               xml_fill_in_time(time_string, wpt->creation_time, 
+                       XML_LONG_TIME);
+               if (time_string[0]) {
+                       gtc_write_xml(0, "<Time>%s</Time>\n", 
+                               time_string);
+               }
+       }
+       gtc_write_xml(1, "<Position>\n");
+       gtc_write_xml(0, "<LatitudeDegrees>%f</LatitudeDegrees>\n", wpt->latitude);
+       gtc_write_xml(0, "<LongitudeDegrees>%f</LongitudeDegrees>\n", wpt->latitude);
+       gtc_write_xml(-1, "</Position>\n");
+       if (wpt->altitude != unknown_alt) {
+               gtc_write_xml(0, "<AltitudeMeters>%f</AltitudeMeters>\n", wpt->altitude);
+       }
+       if (wpt->heartrate) {
+               gtc_write_xml(0, "<HeartRateBpm>%d</HeartRateBpm>\n", wpt->heartrate);
+       }
+
+       gtc_write_xml(-1, "</Trackpoint>\n");
+#endif
+}
+
+static void
+gtc_hdr( const route_head *rte)
+{
+       gtc_write_xml(1,"<Track>\n");
+}
+
+static void
+gtc_ftr(const route_head *rte)
+{
+       gtc_write_xml(-1,"</Track>\n");
+}
+
+static time_t gtc_least_time;
+static time_t gtc_most_time;
+
+static void
+gtc_lap_start(const route_head *rte)
+{
+       gtc_least_time = 0;
+       gtc_most_time = 0;
+}
+
+static void
+gtc_study_lap(const waypoint *wpt)
+{
+       if (wpt->creation_time && (gtc_least_time == 0)) 
+               gtc_least_time = wpt->creation_time;
+
+       if (wpt->creation_time && (gtc_least_time > wpt->creation_time))
+               gtc_least_time =  wpt->creation_time;
+
+       if (wpt->creation_time > gtc_most_time) 
+               gtc_most_time = wpt->creation_time;
+}
+
+static void
+gtc_fake_hdr(void)
+{
+       long secs = 0;
+       if (gtc_least_time && gtc_most_time) {
+               secs = gtc_most_time - gtc_least_time;
+       }
+       gtc_write_xml(0, "<TotalTimeSeconds>%d</TotalTimeSeconds>\n", secs);
+       gtc_write_xml(0, "<DistanceMeters>0</DistanceMeters>\n");
+       gtc_write_xml(0, "<Calories>0</Calories>\n");
+       gtc_write_xml(0, "<AverageHeartRateBpm>0</AverageHeartRateBpm>\n");
+       gtc_write_xml(0, "<MaximumHeartRateBpm>0</MaximumHeartRateBpm>\n");
+       gtc_write_xml(0, "<Intensity>Active</Intensity>\n");
+       gtc_write_xml(0, "<TriggerMethod>Manual</TriggerMethod>\n");
+}
+
+void
+gtc_write(void)
+{
+#if 0
+       fprintf(ofd, "<?xml version=\"1.0\" ?>\n");
+       fprintf(ofd, "<History xmlns=\"http://www.garmin.com/xmlschemas/ForerunnerLogbook\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.garmin.com/xmlschemas/ForerunnerLogbook http://www.garmin.com/xmlschemas/ForerunnerLogbookv1.xsd\" version=\"1\">\n");
+       fprintf(ofd, "    <Run>\n");
+       track_disp_all(gtc_hdr, gtc_ftr, gtc_waypt_pr);
+       fprintf(ofd, "    </Run>\n");
+       fprintf(ofd, "</History>\n");
+#else
+       gtc_write_xml(0, "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>\n");
+       gtc_write_xml(1, "<TrainingCenterDatabase\nxmlns=\"http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v1\"\nxmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\nxsi:schemaLocation=\"http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v1\nhttp://www.garmin.com/xmlschemas/TrainingCenterDatabasev1.xsd\">\n");
+       gtc_write_xml(1, "<History>\n");
+
+       gtc_write_xml(1, "<Running>\n");
+       gtc_write_xml(1, "<Run>\n");
+
+       gtc_lap_start(NULL);
+       track_disp_all(NULL, NULL, gtc_study_lap);
+
+       if (gtc_least_time) {
+               char time_string[100];
+               xml_fill_in_time(time_string, gtc_least_time, XML_LONG_TIME);
+               gtc_write_xml(1, "<Lap StartTime=\"%s\">\n", time_string);
+       } else {
+               gtc_write_xml(1, "<Lap>\n");
+       }
+       gtc_fake_hdr();
+       track_disp_all(gtc_hdr, gtc_ftr, gtc_waypt_pr);
+       gtc_write_xml(1, "</Lap>\n");
+       gtc_write_xml(-1, "</Run>\n");
+       gtc_write_xml(-1, "</Running>\n");
+       gtc_write_xml(0, "<Biking />\n");
+       gtc_write_xml(0, "<Other />\n");
+       gtc_write_xml(0, "<MultiSport />\n");
+
+       gtc_write_xml(-1, "</History>\n");
+       gtc_write_xml(-1, "</TrainingCenterDatabase>\n");
+
+#endif
+}
+
+void   gl_trk_s(const char *args, const char **unused)
+{
+       trk_head = route_head_alloc();
+       track_add_head(trk_head);
+}
+#if 0
+void   gl_trk_ident(const char *args, const char **unused)
+{
+       trk_head->rte_name = xstrdup(args);
+}
+#endif
+
+void   gl_trk_pnt_s(const char *args, const char **unused)
+{
+       wpt_tmp = waypt_new();
+}
+
+void   gl_trk_pnt_e(const char *args, const char **unused)
+{
+       track_add_wpt(trk_head, wpt_tmp);
+}
+
+void   gl_trk_utc(const char *args, const char **unused)
+{
+       wpt_tmp->creation_time = xml_parse_time(args);
+}
+
+void   gl_trk_lat(const char *args, const char **unused)
+{
+       wpt_tmp->latitude = atof(args);
+}
+
+void   gl_trk_long(const char *args, const char **unused)
+{
+       wpt_tmp->longitude = atof(args);
+}
+
+void   gl_trk_alt(const char *args, const char **unused)
+{
+       wpt_tmp->altitude = atof(args);
+}
+
+
+
+ff_vecs_t gtc_vecs = {
+        ff_type_file,
+       { ff_cap_none, ff_cap_write, ff_cap_none},
+        gtc_rd_init,
+        gtc_wr_init,
+        NULL,
+        gtc_wr_deinit,
+        NULL,
+        gtc_write,
+        NULL,
+        gtc_args,
+       CET_CHARSET_ASCII, 0    /* CET-REVIEW */
+};
diff --git a/vecs.c b/vecs.c
index 81ef27ac14a5e3d984fbb8c596b0dbcdaae959cc..e39af20c567d69b319cc54283a96c278dc1281aa 100644 (file)
--- a/vecs.c
+++ b/vecs.c
@@ -109,6 +109,7 @@ extern ff_vecs_t xcsv_vecs;
 extern ff_vecs_t yahoo_vecs;
 extern ff_vecs_t wbt_svecs;
 extern ff_vecs_t wbt_fvecs;
+extern ff_vecs_t gtc_vecs;
 
 static
 vecs_t vec_list[] = {
@@ -593,6 +594,12 @@ vecs_t vec_list[] = {
                "Dell Axim Navigation System (.gpb) file format",
                "gpb"
        },
+       {
+               &gtc_vecs,
+               "gtrnctr",
+               "Garmin Training Center"
+               "xml"
+       },
        {
                NULL,
                NULL,
diff --git a/xmldoc/formats/gtrnctr.xml b/xmldoc/formats/gtrnctr.xml
new file mode 100644 (file)
index 0000000..f590871
--- /dev/null
@@ -0,0 +1,17 @@
+<para>
+Garmin Training Center is the successor to Garmin' Logbook program
+for their workout units.  It is a free upgrade.
+</para>
+<para>
+This format is somewhat underachieving in GPSBabel.  It is a write-only
+format; we never read it.  The bigger problem, however, is a fundamental
+impedance mismatch between this format and most of what we support.  GPSBabel
+fundamentally deals in waypoints, tracks, and routes.  While we do record
+things like heart rate and temperature when we know it, the fundamentals
+of Training Center are different - it deals in concepts like laps and calories
+which are rather alien to GPSBabel and most of the formats we support.  As 
+such, while we can describe the tracks pretty accurately, things like 
+calories and heart zone tracking are not supported.
+</para>
+
+